﻿/******************************************************************************
 * 
 * Announce: CSharpKit, Basic algorithms, components and definitions.
 *           Copyright (C) ShenYongchen.
 *           All rights reserved.
 *   Author: 申永辰.郑州 (shenyczz@163.com)
 *  WebSite: http://github.com/shenyczz/CSharpKit
 *
 * THIS CODE IS LICENSED UNDER THE MIT LICENSE (MIT).
 * THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 
 * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
 * IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
 * PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
 * 
******************************************************************************/

using System;
using CSharpKit.Numerics.Distributions;

namespace CSharpKit.Numerics.LinearAlgebra
{
    /// <summary>
    /// 矢量构造器
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class VectorBuilder<T> : Numeric<T>
        where T : struct, IFormattable, IEquatable<T>
    {
        public Vector<T> OfStorage(VectorStorage<T> storage)
        {
            if (storage == null)
                throw new ArgumentNullException(nameof(storage));

            if (storage is VectorStorageDense<T> dense)
                return Dense(dense);

            if (storage is VectorStorageSparse<T> sparse)
                return Sparse(sparse);

            throw new NotSupportedException(
                string.Format("Vector storage type '{0}' is not supported. " +
                    "Only DenseVectorStorage and SparseVectorStorage are supported as this point.", storage.GetType().Name));
        }


        #region Dense

        public Vector<T> Dense(int length)
        {
            return Dense(new VectorStorageDense<T>(length));
        }
        public Vector<T> Dense(T[] array)
        {
            return Dense(new VectorStorageDense<T>(array.Length, array));
        }
        public Vector<T> Dense(int length, T value)
        {
            // if (Zero.Equals(value)) return Dense(length);
            return Dense(VectorStorageDense<T>.OfValue(length, value));
        }


        /// <summary>
        /// Create a new dense vector and initialize each value using the provided init function.
        /// </summary>
        public Vector<T> Dense(int length, Func<int, T> init)
        {
            return Dense(VectorStorageDense<T>.OfInit(length, init));
        }

        public abstract Vector<T> Dense(VectorStorageDense<T> storage);

        #endregion

        #region Sparse

        public Vector<T> Sparse(int length)
        {
            return Sparse(new VectorStorageSparse<T>(length));
        }
        public Vector<T> Sparse(int length, T value)
        {
            if (Zero.Equals(value)) return Sparse(length);
            return Sparse(VectorStorageSparse<T>.OfValue(length, value));
        }
        public Vector<T> Sparse(int length, Func<int, T> init)
        {
            return Sparse(VectorStorageSparse<T>.OfInit(length, init));
        }

        public abstract Vector<T> Sparse(VectorStorageSparse<T> storage);

        #endregion

        #region Random

        public Vector<T> Random(int length)
        {
            return Random(length, new Normal(SystemRandomSource.Default));
        }
        public Vector<T> Random(int length, int seed)
        {
            return Random(length, new Normal(new SystemRandomSource(seed, true)));
        }



        public abstract Vector<T> Random(int length, IContinuousDistribution distribution);

        #endregion

        #region SameAs

        /// <summary>
        /// 
        /// </summary>
        /// <param name="example"></param>
        /// <typeparam name="TU"></typeparam>
        /// <returns></returns>
        public Vector<T> SameAs<TU>(Vector<TU> example)
            where TU : struct, IEquatable<TU>, IFormattable
        {
            return example.Storage.IsDense
                ? Dense(example.Count)
                : Sparse(example.Count);
        }
        public Vector<T> SameAs<TU>(Vector<TU> example, int length)
            where TU : struct, IEquatable<TU>, IFormattable
        {
            return example.Storage.IsDense
                ? Dense(length)
                : Sparse(length);
        }
        public Vector<T> SameAs(Vector<T> example, Vector<T> otherExample)
        {
            return example.Storage.IsDense || otherExample.Storage.IsDense
                ? Dense(example.Count)
                : Sparse(example.Count);
        }

        /// <summary>
        /// 创建一个新的向量，其类型可以表示并最接近两个提供的样本。<br/>
        /// Create a new vector with a type that can represent and is closest to both provided samples.
        /// </summary>
        public Vector<T> SameAs(Matrix<T> matrix, Vector<T> vector, int length)
        {
            return matrix.Storage.IsDense || vector.Storage.IsDense ? Dense(length) : Sparse(length);
        }

        public Vector<T> SameAs<TU>(Matrix<TU> example, int length)
            where TU : struct, IEquatable<TU>, IFormattable
        {
            return example.Storage.IsDense ? Dense(length) : Sparse(length);
        }

        #endregion



        //}}@@@
    }

}

